package pl.jtb.ctl.tabory.ui.editors;

import javax.print.attribute.standard.Severity;

import org.apache.log4j.Logger;
import org.eclipse.core.runtime.Status;
import org.eclipse.jface.action.Action;
import org.eclipse.jface.dialogs.ErrorDialog;
import org.eclipse.swt.custom.BusyIndicator;
import org.eclipse.swt.widgets.Composite;
import org.eclipse.swt.widgets.Display;
import org.eclipse.swt.widgets.Shell;
import org.eclipse.swt.widgets.ToolItem;
import org.eclipse.ui.forms.widgets.Form;
import org.eclipse.ui.forms.widgets.FormToolkit;
import org.eclipse.ui.part.ViewPart;
import org.eclipse.wb.swt.ResourceManager;

import pl.jtb.ctl.tabory.ui.osgi.UiBundleActivator;
import pl.jtb.ctl.tabory.ui.selection.ISelection;

public abstract class AbstractEditorPart<S extends ISelection> extends ViewPart {

    private final Logger logger = Logger.getLogger(AbstractEditorPart.class);

    protected S selection;

    protected final FormToolkit formToolkit;
    protected Form form;
    protected ToolItem toolItemSave;
    protected ToolItem toolItemCancel;

    protected boolean isDirty;

    protected Action editorSaveAction;
    protected Action editorCancelAction;

    public AbstractEditorPart() throws Exception {
        BusyIndicator.showWhile(Display.getDefault(), new Runnable() {
            @Override
            public void run() {
                try {
                    selection = initSelection();
                } catch (Exception e) {
                    logger.error(e.getMessage(), e);
                    openErrorDialog(e);
                }
            }
        });
        createActions();
        formToolkit = new FormToolkit(Display.getDefault());
        setDirty(false);
    }

    protected void createActions() {
        editorSaveAction = new Action(UiBundleActivator.getMessage("common.save")) {
            @Override
            public void run() {
                if (!isDirty) {
                    logger.debug("Could not save not dirty editor. Dirty flag value is: " + isDirty + ". Something is relly bad");
                    return;
                }
                logger.debug("Run menu action: save editor.");
                BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
                    @Override
                    public void run() {
                        try {
                            doSave();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                            openErrorDialog(e);
                        }
                    }
                });
            }
        };
        editorCancelAction = new Action(UiBundleActivator.getMessage("common.cancel")) {
            @Override
            public void run() {
                if (!isDirty) {
                    logger.debug("Could not cancel not dirty editor. Dirty flag value is: " + isDirty + ". Something is relly bad");
                    return;
                }
                logger.debug("Run menu action: cancel editor.");
                BusyIndicator.showWhile(form.getDisplay(), new Runnable() {
                    @Override
                    public void run() {
                        try {
                            doCancel();
                        } catch (Exception e) {
                            logger.error(e.getMessage(), e);
                            openErrorDialog(e);
                        }
                    }
                });
            }
        };

        editorSaveAction.setImageDescriptor(ResourceManager.getPluginImageDescriptor("org.eclipse.ui", "/icons/full/etool16/save_edit.gif"));
        editorCancelAction.setImageDescriptor(ResourceManager.getPluginImageDescriptor("org.eclipse.ui", "/icons/full/etool16/clear.gif"));
    }

    @Override
    public void createPartControl(Composite parent) {
        logger.debug("Creating part control");
        form = formToolkit.createForm(parent);
        formToolkit.paintBordersFor(form);
        form.getToolBarManager().add(editorSaveAction);
        form.getToolBarManager().add(editorCancelAction);
        form.getToolBarManager().update(true);
        logger.debug("Initializing GUI.");
        initGui(parent);
        logger.debug("Post-initializing GUI.");
        postInitGui(parent);
    }

    protected abstract void initGui(Composite parent);

    protected abstract void postInitGui(Composite parent);

    protected abstract void doSave() throws Exception;

    protected abstract void doCancel() throws Exception;

    protected abstract S initSelection() throws Exception;

    public boolean isDirty() {
        return isDirty;
    }

    public void setDirty(boolean isDirty) {
        logger.debug("Set editor state dirty to: " + isDirty);
        // TODO change editor name if editor is dirty
        this.isDirty = isDirty;
        editorSaveAction.setEnabled(isDirty);
        editorCancelAction.setEnabled(isDirty);
    }

    public void openErrorDialog(Exception e) {
        if (e == null) {
            return;
        }
        String cause;
        if (e.getCause() != null) {
            cause = e.getCause().getLocalizedMessage().toString();
        } else {
            cause = e.getMessage();
        }
        Status status = new Status(Severity.ERROR.getValue(), UiBundleActivator.PLUGIN_ID, cause);
        Shell shell = null;
        if (getSite() != null) {
            shell = getSite().getShell();
        }
        ErrorDialog.openError(shell, UiBundleActivator.getMessage("common.dialog.title.error"), e.getMessage(), status);
    }

}
